<?php
/* 
 * Contains the plugins class
 * @package waterwheel
 */
/*
 *  Copyright 2010 Andrew Rickmann
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */


/**
 * Handles finding, loading, and interfacing with plugins
 *
 * @author Andrew
 */
class plugins {
    
    /**
     *
     * @var Array Contains an array of plugin objects 
     */
    private static $collection = array();


    function  __construct() {
	$this->load_plugins();
    }

    /**
     * Searches the plugin directories and loads all plugins that are found.
     *
     * Any plugins in the specified directories (see below) will be loaded.
     * Waterwheel does not include functionality to turn plugins on or off.
     *
     * Plugin directories:
     * /plugins/
     *
     *
     */
    private function load_plugins(){

	//create a list of directories where plugins can be held
	$plugin_directories = array();
	$plugin_directories[] = APPLICATION_PATH . '/plugins/';

	//loop though all the possible directories
	foreach( $plugin_directories as $plugindir ){
	    //for each directory loop through the files
	    $dir = dir( $plugindir );
	    while( false != ( $subdir = $dir->read() ) ){
		//all plugins must residen in a sub directory
		if ( '.' != $subdir && '..' != $subdir && is_dir( $plugindir . DIRECTORY_SEPARATOR . $subdir ) ){
		    //search the subdirectory for plugin class files
		    //the file name must be {classname}.plugin.php
		    $sdir = dir($plugindir . DIRECTORY_SEPARATOR . $subdir);
		    while( false != ( $filename = $sdir->read() ) ){
			//if the filename has the .plugin.php extension
			if ( strpos( $filename , '.plugin.php' ) != 0 ) {
			    //instantiate the plugin into the collection
			    //include the file
			    include_once( $plugindir . DIRECTORY_SEPARATOR . $subdir . DIRECTORY_SEPARATOR . $filename );
			    //remove the extension to get the class name
			    $classname = str_replace('.plugin.php', '', $filename);
			    //make sure the class is no available
			    if ( class_exists( $classname ) ){
				//instantiate the plugin into the collection
				self::$collection[$classname] = new $classname();
			    } else {
				throw new waterwheelexception('Plugin classname is not included within the plugin file name.');
			    }

			}
		    }
		}
	    }
	}
	plugins::action('plugins_loaded' , $this);
    }

    /**
     * Returns a copy of the plugin array
     *
     * @return Array An array of instantiated plugin objects
     *
     */
    public static function get_loaded(){

	$ca = self::$collection;

	return $ca;
    }

    /**
     * @todo check a copy of the collection to see if a plugin is present
     *
     * @param String $classname the classname of the plugin to check
     * @return Bool True if loaded, False if not.
     */
    public static function is_loaded( $classname ){

	if ( isset( self::$collection[$classname] ) ){
	    return true;
	} else {
	    return false;
	}
    }

    /**
     * Remove a plugin from the loaded plugins list
     *
     * @param string $classname the classname of the plugin to remove
     */
    public static function unload( $classname ){
	unset( self::$collection[$classname]  );
    }

    /**
     * Triggers an action that plugins can hook into
     * A plugin should implement a function called action_{actionname}
     *
     * @param String $actionname The name of the action
     */
    public static function action( $actionname , $vars = array() ){

	//make sure vars is in an array
	if ( !is_array($vars) ){
	    $vars = array($vars);
	}

	//loop through all the loaded plugins
	foreach( self::$collection as $plugin ){
	    //check the method exists
	    $methodname = 'action_' . $actionname;
	    if ( method_exists($plugin, $methodname) ){
		call_user_func_array(array( $plugin , $methodname) , $vars);
	    }
	}
    }

    /**
     * Triggers a filter that plugins can hook into
     * A plugin should implement a function called filter_{filtername}
     *
     * @param String $filtername The name of the filter
     * @param Array $data An array of information to be passed as variables
     * @return Mixed a filtered copy of $data
     */
    public static function filter( $filtername , $data ){

	//make sure data is an array
	if ( !is_array($data) ){
	    $data = array($data);
	}

	//loop through all the loaded plugins
	foreach( self::$collection as $plugin ){
	    //check the method exists
	    $methodname = 'filter_' . $filtername;
	    if ( method_exists($plugin , $methodname) ){
		$data = call_user_func_array( array( $plugin , $methodname ) , $data );
		//check data is not null.
		if ( is_null( $data ) ){
		    //if null assume that is because the function returned nothing
		    //in theory a filter could choose to return a null value
		    //but I think it should not.
		    throw new waterwheelexception('Plugin filter did not return a value.');
		}
	    }
	}
	return $data;
    }



}
?>
